﻿// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)

using System;
using System.Collections.Generic;
using System.Xml;

namespace CXW.Core
{

    public class Condition : ICondition
    {
        string name;
        Properties properties;
        ConditionFailedAction action;
        /// <summary>
        /// Returns the action which occurs, when this condition fails.
        /// </summary>
        public ConditionFailedAction Action
        {
            get { return action; }
            set { action = value; }
        }
        public string Name
        {
            get { return name; }
        }

        public string this[string key]
        {
            get { return properties[key]; }
        }

        public Properties Properties
        {
            get { return properties; }
        }

        public Condition(string name, Properties properties)
        {
            this.name = name;
            this.properties = properties;
            action = properties.Get("action", ConditionFailedAction.Exclude);
        }

        public static ICondition Read(XmlReader reader)
        {
            Properties properties = Properties.ReadFromAttributes(reader);
            string conditionName = properties["name"];
            return new Condition(conditionName, properties);
        }

        public static ICondition ReadComplexCondition(XmlReader reader)
        {
            Properties properties = Properties.ReadFromAttributes(reader);
            reader.Read();
            ICondition condition = null;
            while (reader.Read())
            {
                switch (reader.NodeType)
                {
                    case XmlNodeType.Element:
                        switch (reader.LocalName)
                        {
                            case "And":
                                condition = AndCondition.Read(reader);
                                goto exit;
                            case "Or":
                                condition = OrCondition.Read(reader);
                                goto exit;
                            case "Not":
                                condition = NegatedCondition.Read(reader);
                                goto exit;
                            default:
                                throw new CoreException("Invalid element name '" + reader.LocalName
                                                             + "', the first entry in a ComplexCondition " +
                                                             "must be <And>, <Or> or <Not>");
                        }
                }
            }
            exit:
            if (condition != null)
            {
                ConditionFailedAction action = properties.Get("action", ConditionFailedAction.Exclude);
                condition.Action = action;
            }
            return condition;
        }

        public static ICondition[] ReadConditionList(XmlReader reader, string endElement)
        {
            List<ICondition> conditions = new List<ICondition>();
            while (reader.Read())
            {
                switch (reader.NodeType)
                {
                    case XmlNodeType.EndElement:
                        if (reader.LocalName == endElement)
                        {
                            return conditions.ToArray();
                        }
                        break;
                    case XmlNodeType.Element:
                        switch (reader.LocalName)
                        {
                            case "And":
                                conditions.Add(AndCondition.Read(reader));
                                break;
                            case "Or":
                                conditions.Add(OrCondition.Read(reader));
                                break;
                            case "Not":
                                conditions.Add(NegatedCondition.Read(reader));
                                break;
                            case "Condition":
                                conditions.Add(Condition.Read(reader));
                                break;
                            default:
                                throw new CoreException("Invalid element name '" + reader.LocalName
                                                             + "', entries in a <" + endElement + "> " +
                                                             "must be <And>, <Or>, <Not> or <Condition>");
                        }
                        break;
                }
            }
            return conditions.ToArray();
        }
    }
}
